/**
 * Copyright (c) 2012, Brent Mucci
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **/

#include "mcl_params_rbsp.hpp"

using namespace mcl;

SequenceParameterSetData::SequenceParameterSetData(Bitstream &bitstream)
{
	m_profile_idc          = bitstream.read_bits(8);
	m_constraint_set0_flag = bitstream.read_bits(1);
	m_constraint_set1_flag = bitstream.read_bits(1);
	m_constraint_set2_flag = bitstream.read_bits(1);
	m_constraint_set3_flag = bitstream.read_bits(1);
	m_constraint_set4_flag = bitstream.read_bits(1);
	m_constraint_set5_flag = bitstream.read_bits(1);
	m_reserved_zero_2bits  = bitstream.read_bits(2);
	m_level_idc            = bitstream.read_bits(8);
	m_seq_parameter_set_id = bitstream.read_bits_ue();
	if( m_profile_idc == 100 || m_profile_idc == 110 ||
		m_profile_idc == 122 || m_profile_idc == 244 ||
		m_profile_idc == 44  || m_profile_idc == 83  ||
		m_profile_idc == 86  || m_profile_idc == 118 ||
		m_profile_idc == 128)
	{
		m_chroma_format_idc = bitstream.read_bits_ue();
		if(m_chroma_format_idc == 3)
		{
			m_separate_colour_plane_flag = bitstream.read_bits(1);
		}
		m_bit_depth_luma_minus8   = bitstream.read_bits_ue();
		m_bit_depth_chroma_minus8 = bitstream.read_bits_ue();
		m_qpprime_y_zero_transform_bypass_flag = bitstream.read_bits(1);
		m_seq_scaling_matrix_present_flag      = bitstream.read_bits(1);
		if(m_seq_scaling_matrix_present_flag)
		{
			for(int i = 0; i < ((m_chroma_format_idc != 3) ? 8 : 12); i++)
			{
				m_seq_scaling_list_present_flag[i] = bitstream.read_bits(1);
				if(m_seq_scaling_list_present_flag[i])
				{
					if(i < 6)
					{
						// Put in Scaling List function here <-- Need to implement
					}
					else
					{
						// Scaling list function again here <-- Need to implement
					} // End of IF/ELSE
				} // End of IF
			} // End of FOR
		} // End of IF
	} // End of IF
	m_log2_max_frame_num_minus4 = bitstream.read_bits_ue();
	m_pic_order_cnt_type        = bitstream.read_bits_ue();
	if(m_pic_order_cnt_type == 0)
	{
		m_log2_max_pic_order_cnt_lsb_minus4 = bitstream.read_bits_ue();
	}
	else if(m_pic_order_cnt_type == 1)
	{
		m_delta_pic_order_always_zero_flag      = bitstream.read_bits(1);
		m_offset_for_non_ref_pic                = bitstream.read_bits_se();
		m_offset_for_top_to_bottom_field        = bitstream.read_bits_se();
		m_num_ref_frames_in_pic_order_cnt_cycle = bitstream.read_bits_ue();
		for(int i = 0; i < m_num_ref_frames_in_pic_order_cnt_cycle; i++)
			m_offset_for_ref_frame[i] = bitstream.read_bits_se();
	}
	m_max_num_ref_frames                   = bitstream.read_bits_ue();
	m_gaps_in_frame_num_value_allowed_flag = bitstream.read_bits(1);
	m_pic_width_in_mbs_minus1              = bitstream.read_bits_ue();
	m_pic_height_in_map_units_minus1       = bitstream.read_bits_ue();
	m_frame_mbs_only_flag                  = bitstream.read_bits(1);

	if(!m_frame_mbs_only_flag)
		m_mb_adaptive_frame_field_flag = bitstream.read_bits(1);

	m_direct_8x8_inference_flag = bitstream.read_bits(1);
	m_frame_cropping_flag       = bitstream.read_bits(1);

	if(m_frame_cropping_flag)
	{
		m_frame_crop_left_offset   = bitstream.read_bits_ue();
		m_frame_crop_right_offset  = bitstream.read_bits_ue();
		m_frame_crop_top_offset    = bitstream.read_bits_ue();
		m_frame_crop_bottom_offset = bitstream.read_bits_ue();
	}

	m_vui_parameters_present_flag = bitstream.read_bits(1);
    if(m_vui_parameters_present_flag)
	{
		// VUI_PARAMETERS FUNCTION HERE <-- Need to implement
	}
}
// Page 67
PictureParameterSetRBSP::PictureParameterSetRBSP(Bitstream &bitstream, SequenceParameterSetData &sequenceParameter)
{
	m_pic_parameter_set_id     = bitstream.read_bits_ue();
	m_seq_parameter_set_id     = bitstream.read_bits_ue();
	m_entropy_coding_mode_flag = bitstream.read_bits(1);
	m_bottom_field_pic_order_in_frame_present_flag = bitstream.read_bits(1);
	m_num_slice_groups_minus1  = bitstream.read_bits_ue();
	if(m_num_slice_groups_minus1 > 0)
	{
		m_slice_group_map_type = bitstream.read_bits_ue();
		if(m_slice_group_map_type == 0)
		{
			for(int iGroup = 0; iGroup <= m_num_slice_groups_minus1; iGroup++)
				m_run_length_minus1[iGroup] = bitstream.read_bits_ue();
		}
		else if(m_slice_group_map_type == 2)
		{
			for(int iGroup = 0; iGroup < m_num_slice_groups_minus1; iGroup++)
			{
				m_top_left[iGroup]     = bitstream.read_bits_ue();
				m_bottom_right[iGroup] = bitstream.read_bits_ue();
			}
		}
		else if(m_slice_group_map_type == 3 ||
			    m_slice_group_map_type == 4 ||
				m_slice_group_map_type == 5)
		{
			m_slice_group_change_direction_flag = bitstream.read_bits(1);
			m_slice_group_change_rate_minus1    = bitstream.read_bits_ue();
		}
		else if(m_slice_group_map_type == 6)
		{
			m_pic_size_in_map_units_minus1 = bitstream.read_bits_ue();
			for(int i = 0; i <= m_pic_size_in_map_units_minus1; i++)
			{
				m_slice_group_id[i] = bitstream.read_bits(1); // U(V) ?????
			}
		}
	}
	m_num_ref_idx_l0_default_active_minus1 = bitstream.read_bits_ue();
	m_num_ref_idx_l1_default_active_minus1 = bitstream.read_bits_ue();
	m_weighted_pred_flag     = bitstream.read_bits(1);
	m_weighted_bipred_idc    = bitstream.read_bits(2);
	m_pic_init_qp_minus26    = bitstream.read_bits_se();
	m_pic_init_qs_minus26    = bitstream.read_bits_se();
	m_chroma_qp_index_offset = bitstream.read_bits_se();
	m_deblocking_filter_control_present_flag = bitstream.read_bits(1);
	m_constrained_intra_pred_flag = bitstream.read_bits(1);
	m_redundant_pic_cnt_present_flag = bitstream.read_bits(1);
	if(bitstream.more_rbsp_data())
	{
		m_transform_8x8_mode_flag = bitstream.read_bits(1);
		m_pic_scaling_matrix_present_flag = bitstream.read_bits(1);
		if(m_pic_scaling_matrix_present_flag)
		{
			for(int i = 0; i < 6 + ((sequenceParameter.m_chroma_format_idc != 3) ? 2 : 6)
				* m_transform_8x8_mode_flag; i++)
			{
				m_pic_scaling_list_present_flag[i] = bitstream.read_bits(1);
				if(m_pic_scaling_list_present_flag[i])
				{
					if(i < 6)
					{
						// Then scaling_list <-- Need to implement

					}
					else
					{
						// Different scaling list <-- Need to implement
					}
				} // End IF
			} // End FOR
			m_second_chroma_qp_index_offset = bitstream.read_bits_se();
		} // End IF
	} // End IF
	bitstream.rbsp_trailing_bits();
}

ScalingList::ScalingList(std::vector<char> scalingList, unsigned int sizeOfScalingList, char &useDefaultScalingMatrixFlag)
{
	unsigned int lastScale = 8, nextScale = 8;
	for(unsigned int j = 0; j < sizeOfScalingList; j++)
	{
		if(nextScale != 0)
		{
//			m_delta_scale = bitstream.read_bits_se();
			// Shift right by 8 and & 0xFF, Same as % 256 but much less expensive.
			nextScale = ((lastScale + m_delta_scale + 256) >> 8) & 0xFF;
			useDefaultScalingMatrixFlag = ((j & nextScale) ^ 1);
			// Finish this ***
		}
		scalingList[j] = (nextScale == 0) ? lastScale : nextScale;
		lastScale = scalingList[j];
	}
}